package com.ruoyi.common.filter;

import com.ruoyi.common.annotation.SMConvert;
import com.ruoyi.common.enums.SMConvertType;
import com.ruoyi.common.utils.SM4Utils;
import com.ruoyi.common.utils.SignatureUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;

import static com.ruoyi.common.enums.SMConvertType.SM4_AND_SIGNATURE;


/**
 * 加密拦截器
 * @author zpp
 */
@Slf4j
@Intercepts({
        @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),
})
@Component
public class SM4EncryptInterceptor implements Interceptor {


    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // todo 根据控制规则判断是否开启

        try {
            encryptIfNeeded(invocation);
        } catch (Exception e) {
            throw new RuntimeException("加密或加签失败！！！",e);
        }

        return invocation.proceed();
    }

    public void encryptIfNeeded(Invocation invocation) throws Exception{
        Object[] args = invocation.getArgs();
        Object parameter = args[1];

        if(parameter == null){
            return;
        }

        // 插入 || 更新 操作
        Field[] fields = parameter.getClass().getDeclaredFields();

        // 创建一个 StringBuilder 存储签名字段值
        StringBuilder  signatureBuffer = new StringBuilder();

        for (Field field : fields) {
            if (field.isAnnotationPresent(SMConvert.class)) {
                SMConvert annotation = field.getAnnotation(SMConvert.class);
                SMConvertType convertType = annotation.value();

                field.setAccessible(true);
                Object value = field.get(parameter);

                switch (convertType) {
                    case SM4:
                        log.info("数据库拦截器加密：{}", value);
                        field.set(parameter, SM4Utils.encrypt((String) value));
                        break;
                    case SIGNATURE:
                    case SM4_AND_SIGNATURE:
                        // 江湖规矩 先加密 再签名
                        if (convertType == SM4_AND_SIGNATURE) {
                            field.set(parameter, SM4Utils.encrypt((String) value));
                            value = field.get(parameter);
                        }
                        signatureBuffer.append(value).append("&");
                        break;
                }
            }
        }

        // 开始签名
        if (signatureBuffer.length() > 0) {
            String signature = SignatureUtils.createSignature(signatureBuffer.toString());
            setSignatureField(parameter, signature);
        }
    }

    private void setSignatureField(Object parameter, String signature) throws IllegalAccessException {
        try {
            Field signatureField = parameter.getClass().getDeclaredField("signature");
            signatureField.setAccessible(true);
            signatureField.set(parameter, signature);
        } catch (NoSuchFieldException e) {
            log.error("没有找到signature字段", e);
            throw new RuntimeException("没有找到signature字段", e);
        }
    }



    // 加载拦截器插件
    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }
}
